using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Drawing;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using System.Drawing.Design;
using System.Runtime.Serialization;
using OpenComposite.Workflow.Properties;

namespace OpenComposite.Workflow
{
	[Designer(typeof(InclusiveORDesigner))]
	[ToolboxItem(typeof(InclusiveORActivityToolboxItem))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.toolbox_or.png")]
	public partial class InclusiveORActivity : DecisionActivity
	{
		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			//if (Root.RunType == RunType.Analytic) {
			//    return base.Execute(executionContext);
			//} else if (Root.RunType == RunType.RandomDocuments) {
			if ( EnabledActivities.Count == 0 )
				return ActivityExecutionStatus.Closed;

			HorizontalWorkflowActivity root = WorkflowHelpers.GetRootActivity(this) as HorizontalWorkflowActivity;
			if ( root.UserData[Resources.sJumpData] != null ) {
				List<string> path = root.UserData[Resources.sJumpData] as List<string>;

				Activity act = GetActivityByName(path[0]);
				act.Closed += ContinueAt;
				executionContext.ExecuteActivity(act);

				path.RemoveAt(0);
				if ( path.Count == 0 )
					root.UserData.Remove(Resources.sJumpData);
			} else {

				foreach ( Activity child in EnabledActivities ) {
					ActivityCondition condition = child.GetValue(ConditionalBranchActivity.RuleProperty) as ActivityCondition;
					if ( condition == null || condition.Evaluate(child, executionContext) == true ) {
						child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(ContinueAt);
						executionContext.ExecuteActivity(child);
					}
				}
			}
			return ActivityExecutionStatus.Executing;
			//} else {
			//    return ActivityExecutionStatus.Closed;
			//}
		}

		void ContinueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= this.ContinueAt;
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			foreach ( ActivityExecutionContext ctx in context.ExecutionContextManager.ExecutionContexts ) {
				if ( ctx.Activity.ExecutionStatus == ActivityExecutionStatus.Executing )
					ctx.CancelActivity(ctx.Activity);
			}

			if ( e.ExecutionStatus == ActivityExecutionStatus.Faulting ) return;

			bool okToClose = true;
			foreach ( Activity child in EnabledActivities ) {
				if ( ( child.ExecutionStatus != ActivityExecutionStatus.Closed ) &&
					   ( child.ExecutionStatus != ActivityExecutionStatus.Initialized ) ) {
					okToClose = false;
					break;
				}
			}

			try {
				if ( okToClose )
					WorkflowHelpers.SecureCloseContext(context, ContinueAt);
			} catch ( Exception ex ) {
				MessageBox.Show(ex.ToString());
			}
		}

		protected override ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception)
		{
			executionContext.Activity.Closed += ContinueAt;
			return base.HandleFault(executionContext, exception);
		}

		protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
		{
			bool okToClose = true;

			for ( int n = 0; n < EnabledActivities.Count; n++ ) {
				Activity child = EnabledActivities[n];

				if ( child.ExecutionStatus == ActivityExecutionStatus.Executing ) {
					executionContext.CancelActivity(child);
					okToClose = false;
				} else if ( ( child.ExecutionStatus != ActivityExecutionStatus.Initialized ) && ( child.ExecutionStatus != ActivityExecutionStatus.Closed ) ) {
					okToClose = false;
				}
			}

			if ( executionContext.Activity.ExecutionStatus == ActivityExecutionStatus.Faulting )
				return ActivityExecutionStatus.Faulting;

			if ( okToClose )
				return base.Cancel(executionContext);

			return ActivityExecutionStatus.Canceling;
		}
	}

	public partial class InclusiveORDesigner : DecisionDesigner
	{
		//private Pen outerSymbolPen = new Pen(Brushes.MediumBlue, 2.0F);
		private Pen innerSymbolPenM = new Pen(Brushes.Black, 2.5F);
		private SizeF s = SizeF.Empty;

		protected override void OnPaint(ActivityDesignerPaintEventArgs e)
		{
			if ( !this.IsVisible )
				return;

			base.OnPaint(e);

			//PaintContainedDesigners(e);

			//bounds = new Rectangle(Bounds.X, Bounds.Y + (Bounds.Height / 2) - (height / 2), width, height);

			//// draw start diamond
			//if (e.Graphics.IsVisible(bounds))
			//    PaintSplit(e);
			//else
			//    bounds.Inflate(-10, -10);

			//// change position to end
			//bounds.Inflate(10, 10);

			//bounds.X += Bounds.Width - width;

			//// draw end diamond
			//if (e.Graphics.IsVisible(bounds))
			//    PaintJoin(e);

			//// draw connectors
			//splitPoints = new List<Point>(GetSplitConnections());
			//joinPoints = new List<Point>(GetJoinConnections());
			//innerPoints = new List<Point>(GetInnerConnections(DesignerEdges.Left));

			//// draw split connectors
			//for (int i = 0; i < innerPoints.Count; i++) {
			//    if (e.Graphics.IsVisible(splitPoints[1])) {
			//        if (innerPoints[i].Y < splitPoints[0].Y)
			//            DrawConnectors(e.Graphics,
			//                e.DesignerTheme.ForegroundPen,
			//                new Point[] { splitPoints[0], new Point(splitPoints[0].X, innerPoints[i].Y), innerPoints[i] },
			//                LineAnchor.None, LineAnchor.None);
			//        else if (innerPoints[i].Y == splitPoints[1].Y)
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { splitPoints[1], innerPoints[i] },
			//                LineAnchor.None, LineAnchor.None);
			//        else if (innerPoints[i].Y > splitPoints[2].Y)
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { splitPoints[2], new Point(splitPoints[2].X, innerPoints[i].Y), innerPoints[i] },
			//                LineAnchor.None, LineAnchor.None);
			//        else
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { splitPoints[1], 
			//                    new Point(innerPoints[i].X - ((innerPoints[i].X - splitPoints[1].X) / 2), splitPoints[1].Y), 
			//                    new Point(innerPoints[i].X - ((innerPoints[i].X - splitPoints[1].X) / 2),innerPoints[i].Y), 
			//                    innerPoints[i] },
			//                LineAnchor.None, LineAnchor.None);

			//    }
			//}

			//innerPoints = new List<Point>(GetInnerConnections(DesignerEdges.Right));

			////draw join connectors
			//for (int i = 0; i < innerPoints.Count; i++) {
			//    if (e.Graphics.IsVisible(joinPoints[0])) {
			//        if (innerPoints[i].Y < joinPoints[0].Y)
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { innerPoints[i], new Point(joinPoints[0].X, innerPoints[i].Y), joinPoints[0] },
			//                LineAnchor.None, LineAnchor.ArrowAnchor);
			//        else if (innerPoints[i].Y == joinPoints[1].Y)
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { innerPoints[i], joinPoints[1] },
			//                LineAnchor.None, LineAnchor.ArrowAnchor);
			//        else if (innerPoints[i].Y > joinPoints[2].Y)
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { innerPoints[i], new Point(joinPoints[2].X, innerPoints[i].Y), joinPoints[2] },
			//                LineAnchor.None, LineAnchor.ArrowAnchor);
			//        else
			//            DrawConnectors(e.Graphics,
			//                 e.DesignerTheme.ForegroundPen,
			//                new Point[] { innerPoints[i], 
			//                    new Point(joinPoints[1].X-(int)((joinPoints[1].X-innerPoints[i].X)/1.5), innerPoints[i].Y), 
			//                    new Point(joinPoints[1].X-(int)((joinPoints[1].X-innerPoints[i].X)/1.5), joinPoints[1].Y), 
			//                    joinPoints[1] },
			//                LineAnchor.None, LineAnchor.ArrowAnchor);

			//    }
			//}

			// Debug
			//foreach (Point point in GetInnerConnections(DesignerEdges.Left|DesignerEdges.Right)) {
			//    point.Offset(-5, -5);
			//    e.Graphics.DrawRectangle(pen, new Rectangle(point, new Size(10, 10)));
			//}


		}

		#region Paint Methods
		protected override void PaintSplit(ActivityDesignerPaintEventArgs e)
		{
			base.PaintSplit(e);

			if ( s == SizeF.Empty )
				s = e.Graphics.MeasureString("OR", TextFont).ToSize();

			e.Graphics.DrawString("OR",
				TextFont,
				e.DesignerTheme.ForegroundBrush,
				new PointF(WorkflowHelpers.GetCenter(bounds).X - ( s.Width / 2 ),
					WorkflowHelpers.GetCenter(bounds).Y - ( s.Height / 2 )));
			//bounds.Inflate(-10, -10);

			//e.Graphics.DrawEllipse(innerSymbolPenM, bounds);
		}

		protected override void PaintJoin(ActivityDesignerPaintEventArgs e)
		{
			base.PaintJoin(e);

			//if (s == SizeF.Empty) 
			//    s = e.Graphics.MeasureString("OR", TextFont);

			//e.Graphics.DrawString("OR", 
			//    TextFont,
			//    e.DesignerTheme.ForegroundBrush,
			//    new PointF(WorkflowHelpers.GetCenter(bounds).X - (s.Width / 2),
			//        WorkflowHelpers.GetCenter(bounds).Y - (s.Height / 2)));
			//bounds.Inflate(-10, -10);

			//e.Graphics.DrawEllipse(innerSymbolPenM, bounds);
		}
		#endregion

		protected override void Dispose(bool disposing)
		{
			innerSymbolPenM.Dispose();

			base.Dispose(disposing);
		}

		public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
		{
			if ( activitiesToInsert.Count == 0 )
				return false;

			if ( activitiesToInsert[0] is ConditionalBranchActivity )
				return true;
			else
				return false;
		}
	}

	public class InclusiveORActivityToolboxItem : ActivityToolboxItem
	{
		public InclusiveORActivityToolboxItem(Type type)
			: base(type)
		{
			this.DisplayName = "Inclusive Or";
		}

		private InclusiveORActivityToolboxItem(SerializationInfo info, StreamingContext context)
		{
			Deserialize(info, context);
		}
	}
}
